#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys

sys.path.append('..')
from common_utils import CBBCommonUtils


def get_plugin_info():
    plugin_info = {
        "name": "centos_access_control_024 Configure_log_file_permissions",
        "plugin_id": "centos_access_control_024",
        "plugin_type": "Access Control",
        "info": "Check and set the log files' write permission for other users.",
        "level": "C",
        "module": "Safety reinforcement",
        "author": "fanyi",
        "keyword": "Safety reinforcement",
        "configable": "false"
    }
    return plugin_info


logger = None
cur_user = None
cur_module = None
cur_task = None


def set_plugin_logger(setter, user, module, task, *args, **kwargs):
    global logger, cur_user, cur_module, cur_task
    logger = setter
    cur_user = user
    cur_module = module
    cur_task = task


def make_chmod(rwx):
    r = 4 if rwx[0] == "r" else 0
    w = 2 if rwx[1] == "w" else 0
    x = 1 if rwx[2] == "x" else 0
    cmd_num = r+w+x
    return str(cmd_num)

file_list = ["/var/log/mail", "/var/log/localmessages", "/var/log/cron", "/var/log/secure", "/var/log/messages", "/var/log/maillog", "/var/log/boot.log", "/var/log/spooler"]
rwx_list = ["775", "775", "775", "775", "755", "775", "775", "775"]


def scan(ip, sys_user, sys_pwd, flag=0, reinforce_flag=False):
    des_list = []
    reinforce_file = []
    backup_rwx = []
    error_count = 0
    for i, value in enumerate(file_list):
        scan_cmd = "ls -l " + value
        result, output = CBBCommonUtils.cbb_run_cmd(ip, scan_cmd, username=sys_user, passwd=sys_pwd)
        if not result and len(output) != 0:
            output = output[0].split()[0]
            u_num = make_chmod(str(output[1:4]))
            g_num = make_chmod(str(output[4:7]))
            o_num = make_chmod(str(output[7:10]))
            if int(u_num+g_num+o_num) <= int(rwx_list[i]):
                des = value + " permissions is SAFE. Now is {}".format(u_num+g_num+o_num)
                logger.debug_info(cur_user, cur_module, cur_task+'_Scan', '', des)
            else:
                error_count += 1
                des = value + " permissions is DANGEROUS. Now is {}".format(u_num+g_num+o_num)
                reinforce_file.append(value)
                backup_rwx.append(u_num+g_num+o_num)
                logger.debug_warning(cur_user, cur_module, cur_task + '_Scan', '', des)
            des_list.append(des)
        elif "No such" in result[0]:
            des = value + " file not found."
            des_list.append(des)
            logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', des)
        else:
            des = "Failed to view file \"{}\" permissions.".format(value)
            des_list.append(des)
            logger.debug_error(cur_user, cur_module, cur_task + '_Scan', '', des)
    if reinforce_flag:
        return des_list, error_count
    des_list.append("Scan Complete.")
    logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', 'Scan Complete.')
    if error_count != 0 and flag == 1:
        reinforce_des, reinforce_err = reinforce(ip, reinforce_file, backup_rwx, sys_user, sys_pwd)
        if reinforce_err == 0:
            error_count = 0
            des_list.extend(reinforce_des)
        else:
            error_count += 1
            des_list.extend(reinforce_des)
    return des_list, error_count


def reinforce(ip, reinforce_file, backup_rwx, sys_user, sys_pwd):
    des_list = []
    error_count = 0
    for i, value in enumerate(reinforce_file):
        backup_cmd = "echo '" + value + " " + backup_rwx[i] + "' >> /var/log/logfile_rwx.`date +%Y-%m-%d`"
        CBBCommonUtils.cbb_run_cmd(ip, backup_cmd, username=sys_user, passwd=sys_pwd)
    check_cmd = "ls /var/log/ | grep logfile_rwx.`date +%Y-%m-%d`"
    check_result, check_output = CBBCommonUtils.cbb_run_cmd(ip, check_cmd, username=sys_user, passwd=sys_pwd)
    if not check_result and len(check_output) != 0:
        backup_check_des = "Backup SUCCEED."
        logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', backup_check_des)
    else:
        error_count += 1
        backup_check_des = "Backup check FAILED."
        logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', backup_check_des)
        des_list.append(backup_check_des)
        return des_list, error_count
    for i, value in enumerate(reinforce_file):
        file_num = file_list.index(value)
        reinforce_cmd = "chmod " + rwx_list[file_num] + " " + file_list[file_num]
        CBBCommonUtils.cbb_run_cmd(ip, reinforce_cmd, username=sys_user, passwd=sys_pwd)
    # 判断权限是否更改成功
    des_reinforce_scan, error_reinforce_scan = scan(ip, sys_user, sys_pwd, flag=0, reinforce_flag=True)
    error_count = error_count + error_reinforce_scan
    if error_count != 0:
        # 加固失败，回滚
        des = "Reinforce FAILED."
        des_list.append(des)
        logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', des)
        rollback_des, rollback_err = rollback(ip, sys_user, sys_pwd)
        des_list.extend(rollback_des)
        return des_list, error_count
    des_list.append("Reinforce Complete.")
    logger.debug_info(cur_user, cur_module, cur_task+'_Reinforce', '', "Reinforce Complete.")
    return des_list, error_count


def rollback(ip, sys_user, sys_pwd):
    des_list = []
    error_count = 0
    # 查找备份文件，若无原权限记录文件则无需或无法回滚
    grep_cmd = "ls /var/log/ | grep logfile_rwx.*"
    result, output = CBBCommonUtils.cbb_run_cmd(ip, grep_cmd, username=sys_user, passwd=sys_pwd)
    if not result and len(output) != 0:
        logger.debug_info(cur_user, cur_module, cur_task+'_Rollback', '', "Backup file FOUND.")
        target = output[len(output) - 1].replace("\n", "")
        cmd = "cat /var/log/" + target
    else:
        error_count = -1
        des_list.append("Backup file NOT FOUND.")
        logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', "Backup file not found.")
        return des_list, error_count
    # 打开记录文件，查看原权限
    result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
    if not result and len(output) != 0:
        for i in output:
            file_name = i.strip().split()[0]
            file_rwx = i.strip().split()[1]
            cmd = "chmod " + file_rwx + " " + file_name
            CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
        des_list.append("Rollback Complete.")
        logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Rollback Complete.")
        del_cmd = "rm -rf /var/log/" + target
        result, output = CBBCommonUtils.cbb_run_cmd(ip, del_cmd, username=sys_user, passwd=sys_pwd)
        if not result:
            del_des = "Backup file deleted. Target is {}.".format(target)
            logger.debug_info(cur_user, cur_module, cur_task+'_Rollback', '', del_des)
        else:
            error_count += 1
            del_des = "Backup file delete FAILED."
            des_list.append(del_des)
            logger.debug_error(cur_user, cur_module, cur_task+'_Rollback', '', del_des)
            return des_list, error_count
    else:
        error_count += 1
        des = "Check backup file FAILED."
        des_list.append(des)
        logger.debug_error(cur_user, cur_module, cur_task+'_Rollback', '', des)
    return des_list, error_count


def check(ip, *args, **kwargs):
    sys_user = kwargs.get("system_user")
    sys_pwd = kwargs.get("system_pwd")
    comm = kwargs.get("command")
    try:
        des_list = []
        des_start = "centos_access_control_024 Start."
        logger.debug_info(cur_user, cur_module, cur_task+'_Check', '', des_start)
        if comm == 1:
            des_scan, error_scan = scan(ip, sys_user, sys_pwd, flag=0)
            des_list.extend(des_scan)
            step_error = int(error_scan)
        elif comm == 2:
            des_reinforce, error_reinforce = scan(ip, sys_user, sys_pwd, flag=1)
            des_list.extend(des_reinforce)
            step_error = int(error_reinforce)
        elif comm == 3:
            des_rollback, error_rollback = rollback(ip, sys_user, sys_pwd)
            des_list.extend(des_rollback)
            step_error = int(error_rollback)
        else:
            return {"code": 3, "count": 0, "des": ['command must be 1/2/3']}
        des_end = "centos_access_control_024 Complete."
        logger.debug_info(cur_user, cur_module, cur_task+'_Check', '', des_end)
        if step_error == 0:
            code = 0
        elif step_error <= -1:
            code = 2
        else:
            code = 1
        return {"code": code, "count": step_error, "des": des_list}
    except Exception as er:
        code = 1
        des = ["ERROR:", str(er)]
        logger.debug_error(cur_user, cur_module, cur_task+'_Check', '', des)
        return {"code": code, "count": 0, "des": des}
